package lostland.gmud.exv2.js;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

import lostland.gmud.exv2.Game;
import lostland.gmud.exv2.LoadingScreen;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeJavaObject;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

import com.orhanobut.logger.Logger;

/**
 * Created by 12548 on 2015/9/13.
 */
public class JsCommon {

	private static String[] simpleScripts = null;
	public static String getSimpleScripts(int index){
		if(simpleScripts == null) {
			simpleScripts = LoadingScreen.loadSimpleScriptsJson();
		}
		return simpleScripts[index];
	}

	/**
	 * 执行JS
	 *
	 * @param js js代码
	 * @param functionName js方法名称
	 * @param functionParams js方法参数
	 * @return
	 */
	public static String runScript(String js, String functionName, Object[] functionParams) {
		Context rhino = Context.enter();

		rhino.setOptimizationLevel(-1);
		try {
			Scriptable scope = rhino.initStandardObjects();

			ScriptableObject.putProperty(scope, "javaContext", Context.javaToJS(Game.getInstance(), scope));
			ScriptableObject.putProperty(scope, "javaLoader", Context.javaToJS(Game.class.getClassLoader(), scope));

			ScriptableObject.putProperty(scope, "room", Context.javaToJS(JsRoom.getInstance(), scope));

			rhino.evaluateString(scope, js, "Game", 1, null);

//			Logger.d("test ss: " + Context.toString(ss));

			Function function = (Function) scope.get(functionName, scope);

			Object result = function.call(rhino, scope, scope, functionParams);
			if (result instanceof String)
				return (String) result;
			else if (result instanceof NativeJavaObject)
				return (String) ((NativeJavaObject) result).getDefaultValue(String.class);
			else if (result instanceof NativeObject) return (String) ((NativeObject) result).getDefaultValue(String.class);
			return result.toString();//(String) function.call(rhino, scope, scope, functionParams);
		} finally {
			Context.exit();
		}
	}

	public static String loadScript(String filename){

		Game game = Game.getInstance();
		try {
			InputStream is = game.getFileIO().readAsset(filename);

			InputStreamReader isr = new InputStreamReader(is, Charset.defaultCharset());
			BufferedReader br = new BufferedReader(isr);
			String s = "";
			while(true){
				String t = br.readLine();

				if(t == null) {
					break;
				}

				s += t;
			}

			br.close();

			return s;

		} catch(IOException e) {
			e.printStackTrace();
		}


		return "";
	}

	static Context rhino;
	public static Context getRhino(){
		if(rhino == null){
			rhino = Context.enter();
			rhino.setOptimizationLevel(-1);
		}
		return rhino;
	}

	public static Scriptable prepareScriptToExec(String js){
		rhino = Context.enter();
		rhino.setOptimizationLevel(-1);

		Scriptable scope = getRhino().initStandardObjects();

		ScriptableObject.putProperty(scope, "javaContext", Context.javaToJS(Game.getInstance(), scope));
		ScriptableObject.putProperty(scope, "javaLoader", Context.javaToJS(Game.class.getClassLoader(), scope));

		ScriptableObject.putProperty(scope, "room", Context.javaToJS(JsRoom.getInstance(), scope));

		getRhino().evaluateString(scope, js, "Game", 1, null);

		return scope;
	}

	public static String execScriptFunction(Scriptable scope, String functionName, Object[] functionParams){
		Function function = (Function) scope.get(functionName, scope);

		Object result = function.call(getRhino(), scope, scope, functionParams);
		if (result instanceof String)
			return (String) result;
		else if (result instanceof NativeJavaObject)
			return (String) ((NativeJavaObject) result).getDefaultValue(String.class);
		else if (result instanceof NativeObject) return (String) ((NativeObject) result).getDefaultValue(String.class);
		return result.toString();//(String) function.call(rhino, scope, scope, functionParams);

	}

	public static void execScriptOver(){
		Context.exit();
		rhino = null;
	}

	public static void test1(){
		String script = loadScript("script/test1.js");
		Logger.d("Script Loaded : " + script);

		Logger.d("" + runScript(script, "hello", new Object[]{}));
	}

	public static void test2(){
		String script = loadScript("script/test2.js");

		new LinearScriptScreen(script).pushToGame();
	}
}
